import viewpoints
import utils
import templates
import types_
import copy


def listConstructors():
    print "viepoint constructors:"
    utils.list_sub_classes('constructors','VPConstructor')


class VPConstructor():
    def __init__(self):
        pass

    displayInfo = False

class LinkedVP(viewpoints.VP,VPConstructor):
    """[VP] --> VP: Takes a list of  VP and
                    returns a VP that applies all VP in the list,
                    returning a list of values
    """
    displayInfo = True

    def __init__(self,shortname="linked",longname="lkd",*linked_vps):
        self.shortname = shortname
        self.longname = longname

        viewpoints.VP.__init__(self)
        VPConstructor.__init__(self)
        self.linked_vps = utils.flatten(linked_vps)

        self.__doc__ = "[" + ", ".join(map(lambda x: str(x.shortname),self.linked_vps)) + "]" 

    def __repr__(self):
        return self.longname

    # Apply every viewpoint, then merge results
    # TODO: for this to work, we need to define results better
    #       and know what to do if the linked_vp return more than
    #       one result per note (match-and-merge by default.  I.E. by default, avoid
    #       combinatorial explosion.  Compute only if required by an option

    def apply(self,stream,*args,**keywords):
        try: slice_ = keywords['slice']
        except KeyError: slice_ = False

        # TODO: how/when to select the material for the demo
        # The demo material must contain the template at least once
        # And must ressemble the structure of the stream
        sliced_stream = copy.deepcopy(stream)

        if slice_:
            sliced_stream = templates.Template().slice_stream(stream,slice_)

        result_dicts = map(lambda x:x.computeResultDict(sliced_stream),self.linked_vps)



        # Iterate and join the results
        if result_dicts[0]:
            first_dict = result_dicts.pop(0)
            for note_id,(note,feature) in first_dict.items():
                add_to_lyric = [feature]
                for dict_ in result_dicts:
                    if dict_[note.id]:
                        (note_i,feature_i) = dict_[note.id]
                        add_to_lyric.append(feature_i)

                if note.lyric:
                    note.lyric = note.lyric + "\n" + "(" + ",\n".join(
                        map(
                            lambda feature: str(feature.name) + " : " + str(feature.value),
                            add_to_lyric
                            )
                        ) + ")"
                else:
                    note.lyric = "(" + ",\n".join(map(lambda feature: str(feature.name)+" : "+str(feature.value),add_to_lyric)) + ")"

        return sliced_stream
